package com.schoolpro.service.impl;


import com.schoolpro.constant.BooleanConstant;
import com.schoolpro.exception.ItemException;
import com.schoolpro.exception.ParamValidationException;
import com.schoolpro.mapper.CategoryMapper;
import com.schoolpro.mapper.CategoryPropertyMapper;
import com.schoolpro.mapper.ItemMapper;
import com.schoolpro.mapper.ValueMapper;
import com.schoolpro.pojo.DO.CategoryDO;
import com.schoolpro.pojo.DO.ItemDO;
import com.schoolpro.pojo.DTO.ItemAddDTO;
import com.schoolpro.pojo.DTO.PropertyDTO;
import com.schoolpro.pojo.DTO.ValueDTO;
import com.schoolpro.service.ItemService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author : Hinton
* @时间 : 2月 05 22:17
*/


@Service
@Slf4j
public class ItemServiceImpl implements ItemService {
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private CategoryPropertyMapper propertyMapper;
    @Autowired
    private ValueMapper valueMapper;
    @Autowired
    private ItemMapper itemMapper;

/*     @Override
    @Transactional
    public void addItem(ItemAddDTO itemAddDTO) {

        // 1. 获得添加的表及其属性
        Integer categoryId = itemAddDTO.getCategoryId();
        if (categoryId == null) {
            throw new ItemException("类目不存在");
        }

        // 1,1 获得category
        CategoryDO categoryDO = categoryMapper.getById(categoryId);
        // 1.2 获得property属性
        List<PropertyDO> propertyDTOList = propertyMapper.getByCategoryName(categoryDO.getName());
        // 1.3 获得可枚举值的value
        // List<ValueDTO> enumValuesList = valueMapper.getByCategoryPropertyName(categoryDO.getName());

        // 2 校验属性是否符合要求
        // 2.1 校验property
        List<ItemDTO > itemDTOList = itemAddDTO.getItemDTOList();

        List<PropertyDO> propertyDTOList2 = propertyMapper.getByCategoryName(categoryDO.getName());

        // 遍历每一条数据
        for (ItemDTO itemDTO: itemDTOList) {
        }

        // 3 添加到item表

    } */

    /**
     * 批量添加item
     * @param itemAddDTOList
     */
    @Override
    @Transactional
    public void addItemBatch(List<ItemAddDTO> itemAddDTOList) {

        for (ItemAddDTO itemAddDTO: itemAddDTOList) {

            // 1. 获得category 和 property等信息
            Integer categoryId = itemAddDTO.getCategoryId();

            // 1.1 获得 category
            CategoryDO categoryDO = categoryMapper.getById(categoryId);
            if (categoryDO == null) {
                throw new ItemException("分类[" + categoryId + "]不存在");
            }

            // 1.2 获得 property 列表
            List<PropertyDTO> propertyDTOList = propertyMapper.getByCategoryName(categoryDO.getName());
            propertyDTOList.forEach(propertyDTO -> {
                // 1.2.1 设置category
                List<ValueDTO> enumValues = valueMapper.getByCategoryPropertyName(categoryDO.getName(), propertyDTO.getName());
                propertyDTO.setEnumValues(enumValues);
            });

            if (CollectionUtils.isEmpty(propertyDTOList)) {
                throw new ItemException("类目[" + categoryDO.getName() + "]未定义任何属性");
            }
            // 1.3 转换为Map<属性名, PropertyDO>，提升查找效率
            Map<String, PropertyDTO> propertyMap = propertyDTOList.stream()
                    .collect(Collectors.toMap(PropertyDTO::getName, Function.identity()));
            log.info("属性Map: {}", propertyMap);

            // 1.4 数据库添加时的list
            ItemDO itemDO = new ItemDO();
            itemDO.setCategory(categoryDO.getName());
            itemDO.setVersion(1);
            List<ItemDO> itemDOList = new ArrayList<>();

            // 2. 遍历元素
            List<Map<String, Object>> itemDTOList = itemAddDTO.getItemDTOList();
            for (Map<String, Object> itemDTO: itemDTOList) {
                log.info("itemDTO: {}", itemDTO);

                // 校验参数
                for (Map.Entry<String, PropertyDTO> entry : propertyMap.entrySet()) {
                    String name = entry.getKey();
                    Object value = itemDTO.get(name);

                    if (!itemDTO.containsKey(name)) {
                        itemDOList.clear();
                        throw new ItemException("属性[" + name + "]不存在");
                    }

                    String checkResult = checkItemDTO(value, propertyMap.get(name));
                    if (BooleanConstant.FAIL.equals(checkResult)) {
                        itemDOList.clear();
                        throw new ItemException("属性[" + name + "]值不符合要求");
                    } else if (BooleanConstant.VALUE_BE_DEFAULT.equals(checkResult)) {
                        // 修改为默认值
                        itemDTO.put(name, propertyMap.get(name).getDefaultValue());
                    }

                }

                // setCategory在上述已设置
                itemDO.setProperties(itemDTO.toString());
                itemDOList.add(itemDO);
            }

            // 3. 添加到 item 表
            log.info("添加到item表{}组数据", itemDOList.size());
            itemMapper.insertBatch(itemDOList);
        }


    }

    private String checkItemDTO(Object value, PropertyDTO propertyDTO) {
        log.info( "校验值[{}]", value);
        log.info("要求{}", propertyDTO);

        // 1. 是否必填
        if (propertyDTO.getRequired() == 1 && value == null) {
            throw new ParamValidationException(propertyDTO.getName() + "需要是必填");
        }

        // 2. 最大长度
        if (propertyDTO.getMaxLength() != null && value != null && value.toString().length() > propertyDTO.getMaxLength()) {
            throw new ParamValidationException(propertyDTO.getName() + "长度不能超过" + propertyDTO.getMaxLength());
        }

        // 3. 数据类型
        switch (propertyDTO.getDataType().toLowerCase()) {
            case "varchar":
                if (value != null && !(value instanceof String)) {
                    throw new ParamValidationException(String.format("%s 类型错误, 应该是 string, 但得到了 %s",
                            propertyDTO.getName(), value.getClass().getSimpleName()));
                }
                break;
            case "int":
                if (value instanceof String) {
                    try {
                        // 尝试将字符串转换为整数
                        Integer.parseInt((String) value);
                    } catch (NumberFormatException e) {
                        throw new ParamValidationException(String.format("%s 类型错误, 应该是 int, 但得到了非数字字符串 %s", propertyDTO.getName(), value));
                    }
                } else if (value != null && !(value instanceof Integer)) {
                    throw new ParamValidationException(String.format("%s 类型错误, 应该是 int, 但得到了 %s",
                            propertyDTO.getName(), value.getClass().getSimpleName()));
                }
                break;
            default:
                throw new ParamValidationException("未知的数据类型: " + propertyDTO.getDataType());
        }

        // 4. 默认值
        if (propertyDTO.getDefaultValue() != null && value == null) {
            log.info("[{}]需要被设置默认值[{}]", propertyDTO.getName(), propertyDTO.getDefaultValue());
            return BooleanConstant.VALUE_BE_DEFAULT;

        }

        // 5. 枚举
        if (propertyDTO.getEnumerable() == 1) {
            List<ValueDTO> enumValues = propertyDTO.getEnumValues();

            if ((enumValues == null ||
                    enumValues.stream()
                            .noneMatch(valueDTO -> valueDTO.getId().toString().equals(value))  ) && enumValues != null) {

                    throw new ParamValidationException("值[" + value + "]不是枚举值, 应该是" +
                            enumValues.stream()
                                    .map(v -> v.getId().toString())
                                    .collect(Collectors.joining(", ", "[", "]")) + "之一");
            }

        }


        return BooleanConstant.SUCCESS;
    }
}
